// SymbianOSUnitConsoleMain.cpp
/*
Created by Roman Savelyev
*/

#include "SymbianOSUnitConsoleMain.h"
#include "testdriver.h"
#include <e32cons.h>

const TUint16 KLineSeparator = 0x2028;
_LIT(KLineTerminatorString, "\n");
const TInt KMaxTestOutput = 2048;
_LIT(KSymbianOsUnit,"Symbian OS Unit");

_LIT(KArrowSelector, ">");
_LIT(KSelectionEraser, " ");

CSymbianOSUnitConsoleMain* CSymbianOSUnitConsoleMain::NewLC()
	{
	CSymbianOSUnitConsoleMain* self = new(ELeave) CSymbianOSUnitConsoleMain;
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CSymbianOSUnitConsoleMain::CSymbianOSUnitConsoleMain() : CActive(CActive::EPriorityIdle),
	iFailedTest(EFalse),
	iTestOutput(NULL),
	iConsole(NULL),
	iSuite(KAllTestSuites)
	{
	CActiveScheduler::Add(this);
	}

void CSymbianOSUnitConsoleMain::ConstructL()
	{
	iTestOutput = HBufC::NewL(KMaxTestOutput);
	iConsole = Console::NewL(KSymbianOsUnit, TSize(KConsFullScreen, KConsFullScreen));
	iConsole->SetCursorHeight(0);
	}

CSymbianOSUnitConsoleMain::~CSymbianOSUnitConsoleMain()
	{
	Cancel();
	delete iConsole;
	delete iTestOutput;
	}

void CSymbianOSUnitConsoleMain::ExecuteUiL()
	{
	CDesCArrayFlat* suiteNames = new (ELeave) CDesCArrayFlat(3);
	CleanupStack::PushL(suiteNames);
	TestDriver::TestSuiteNamesL(*suiteNames);
	iConsole->Write(_L("Choose testsuite to execute:\n"));
	TInt firstSuite = 0;
	iConsole->Write(KArrowSelector);
	iConsole->Write(KSelectionEraser);
	if (1 < suiteNames->MdcaCount())
		{
		firstSuite = KAllTestSuites;
		iConsole->Write(_L("All testsuites\n"));
		TInt count = suiteNames->MdcaCount();
		for (TInt i=0; i<count; i++)
			{
			iConsole->Write(_L("  "));
			iConsole->Write(suiteNames->MdcaPoint(i));
			iConsole->Write(_L("\n"));
			}
		}
	else
		{
		iConsole->Write(suiteNames->MdcaPoint(0));
		iConsole->Write(_L("\n"));
		}
	TInt suiteIndex = 0;
	for (TBool keepGetching = ETrue; keepGetching;)
		{
		iConsole->Getch();
		TKeyCode code = iConsole->KeyCode();
		switch (code)
			{
			case EKeyDownArrow:
				{
				iConsole->SetPos(0, 1 + suiteIndex);
				iConsole->Write(KSelectionEraser);
				suiteIndex++;
				suiteIndex %= suiteNames->MdcaCount() - firstSuite;
				iConsole->SetPos(0, 1 + suiteIndex);
				iConsole->Write(KArrowSelector);
				break;
				}
			case EKeyUpArrow:
				{
				iConsole->SetPos(0, 1 + suiteIndex);
				iConsole->Write(KSelectionEraser);
				suiteIndex--;
				if (0 > suiteIndex)
					{
					suiteIndex = suiteNames->MdcaCount() - firstSuite - 1;
					}
				iConsole->SetPos(0, 1 + suiteIndex);
				iConsole->Write(KArrowSelector);
				break;
				}
			case EKeyEnter:
				{
				keepGetching = EFalse;
				break;
				}
			default:
				{
				// keep getch'ing
				break;
				}
			}
		}
	CleanupStack::PopAndDestroy(suiteNames);
	iConsole->ClearScreen();
	iConsole->SetPos(0, 0);
	Execute(suiteIndex + firstSuite);
	}

void CSymbianOSUnitConsoleMain::Execute(TInt aSuite)
	{
	iSuite = aSuite;
	iStatus = KRequestPending;
	SetActive();
	TRequestStatus* status = &iStatus;
	User::RequestComplete(status, KErrNone);
	}

TInt CSymbianOSUnitConsoleMain::ExecutionError() const
	{
	return iError;
	}

void CSymbianOSUnitConsoleMain::RunL()
	{
	iTestOutput->Des().Zero();
	iFailedTest = EFalse;
	TestDriver testDriver(iTestOutput,this);
	testDriver.runAllSuitesL(iSuite);
	DisplayEachTestResult();
	iConsole->Write(_L("\n"));
	iConsole->Write(_L("----------------------------\n"));
	if (iFailedTest)
		{
		iConsole->Write(_L(" _______    ___       __   __      \n"));
		iConsole->Write(_L("|   ____|  /   \\     |  | |  |     \n"));
		iConsole->Write(_L("|  |__    /  ^  \\    |  | |  |     \n"));
		iConsole->Write(_L("|   __|  /  /_\\  \\   |  | |  |     \n"));
		iConsole->Write(_L("|  |    /  _____  \\  |  | |  `----.\n"));
		iConsole->Write(_L("|__|   /__/     \\__\\ |__| |_______|\n"));
		}
	else
		{
		iConsole->Write(_L(".______      ___           _______.     _______.\n"));
		iConsole->Write(_L("|   _  \\    /   \\         /       |    /       |\n"));
		iConsole->Write(_L("|  |_)  |  /  ^  \\       |   (----`   |   (----`\n"));
		iConsole->Write(_L("|   ___/  /  /_\\  \\       \\   \\        \\   \\    \n"));
		iConsole->Write(_L("|  |     /  _____  \\  .----)   |   .----)   |   \n"));
		iConsole->Write(_L("| _|    /__/     \\__\\ |_______/    |_______/    \n"));
		}
	iConsole->Write(_L("[press any key]\n"));
	iConsole->Getch();
	CActiveScheduler::Stop();
	}

TInt CSymbianOSUnitConsoleMain::RunError(TInt aError)
	{
	iError = aError;
	CActiveScheduler::Stop();
	return KErrNone;
	}

void CSymbianOSUnitConsoleMain::DoCancel()
	{
	// nothing to do
	}

void CSymbianOSUnitConsoleMain::DisplayEachTestResult()
	{
	iConsole->ClearScreen();
	iConsole->SetPos(0, 0);
	TPtrC ptr(iTestOutput->Des());
	while (0 < ptr.Length())
	    {
	    TInt pos = ptr.Locate(KLineSeparator);
	    if (KErrNotFound == pos)
	        {
	        break;
	        }
	    iConsole->Write(ptr.Left(pos));
	    iConsole->Write(KLineTerminatorString);
	    ptr.Set(ptr.Mid(pos + 1));
	    }
	iConsole->Write(ptr);
	}

void CSymbianOSUnitConsoleMain::FailedTest()
	{
	iFailedTest = ETrue;
	}
///////////////////////////////////////////////////////////////////////////////
LOCAL_C void DoMainL()
	{
	CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
	CleanupStack::PushL(scheduler);
	CActiveScheduler::Install(scheduler);

	CSymbianOSUnitConsoleMain* console = CSymbianOSUnitConsoleMain::NewLC();
	console->ExecuteUiL();

	CActiveScheduler::Start();

	User::LeaveIfError(console->ExecutionError());

	CleanupStack::PopAndDestroy(2, scheduler);
	}

GLDEF_C TInt E32Main()
	{
	__UHEAP_MARK;
	CTrapCleanup* cleanup = CTrapCleanup::New();

	TRAPD(mainError, DoMainL());

	delete cleanup;
	__UHEAP_MARKEND;
	return mainError;
	}

